package com.carleasoft.mps.cms.business.leave.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.carleasoft.mps.cms.business.clerk.bean.vo.CategoryDoorVo;
import com.carleasoft.mps.cms.business.leave.bean.entity.LeaveEntity;
import com.carleasoft.mps.cms.business.leave.bean.entity.LeaveReportUserEntity;
import com.carleasoft.mps.cms.business.leave.bean.entity.ReportEntity;
import com.carleasoft.mps.cms.business.leave.bean.po.AttendancePo;
import com.carleasoft.mps.cms.business.leave.bean.po.LeavePo;
import com.carleasoft.mps.cms.business.leave.bean.po.ReportPo;
import com.carleasoft.mps.cms.business.leave.bean.vo.AttendanceVo;
import com.carleasoft.mps.cms.business.leave.bean.vo.CountLeaveAndReportVo;
import com.carleasoft.mps.cms.business.leave.bean.vo.UserListVo;
import com.carleasoft.mps.cms.business.leave.dao.LeaveMapper;
import com.carleasoft.mps.cms.business.leave.dao.ReportMapper;
import com.carleasoft.mps.cms.business.leave.service.LeaveReportUserService;
import com.carleasoft.mps.cms.business.leave.service.LeaveService;
import com.carleasoft.mps.cms.business.leave.service.ReportService;
import com.carleasoft.mps.core.user.ThreadUserContext;
import com.carleasoft.mps.core.user.UserCacheData;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author: yangHao
 * @createDate:2023/6/3
 * @description:
 */
@Service
public class ReportServiceImpl extends ServiceImpl<ReportMapper, ReportEntity> implements ReportService {

    @Autowired
    private LeaveService leaveService;
    @Autowired
    private LeaveReportUserService leaveReportUserService;
    @Autowired
    private LeaveMapper leaveMapper;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public String saveReport(ReportPo reportPo) {
        List<String> userList = reportPo.getUserList();
        List<UserListVo> userInfos = leaveMapper.userInfo(userList);
        Map<String, UserListVo> map = userInfos.stream().collect(Collectors.toMap(UserListVo::getUserCode, Function.identity()));
        List<LeaveReportUserEntity> leaveReportUserEntities = new ArrayList<>();
        for (String s : userList) {
            LeaveReportUserEntity leaveReportUserEntity = new LeaveReportUserEntity();
            leaveReportUserEntity.setUserCode(s);
            leaveReportUserEntity.setUserName(map.get(s).getUserName());
            leaveReportUserEntities.add(leaveReportUserEntity);
        }
        reportPo.setLeaveReportUserEntities(leaveReportUserEntities);
        UserCacheData user = ThreadUserContext.getCurrentCacheUser();
        if (StrUtil.isNotBlank(reportPo.getReportCode())) {
            ReportEntity entity = this.getOne(Wrappers.<ReportEntity>lambdaQuery()
                    .eq(ReportEntity::getReportCode, reportPo.getReportCode()));
            leaveReportUserService.remove(Wrappers.<LeaveReportUserEntity>lambdaQuery()
                    .eq(LeaveReportUserEntity::getLeaveReportCode, reportPo.getReportCode()));
            entity.setStatus(1);
            entity.setCreateTime(LocalDateTime.now());
            entity.setCreatePersonCode(user.getUserCode());
            entity.setCreatePersonName(user.getUserName());
            entity.setUpdateTime(LocalDateTime.now());
            entity.setUpdatePersonCode(user.getUserCode());
            entity.setUpdatePersonName(user.getUserName());
            this.updateById(entity);
            for (LeaveReportUserEntity leaveReportUserEntity : reportPo.getLeaveReportUserEntities()) {
                leaveReportUserEntity.setCode(IdWorker.getIdStr());
                leaveReportUserEntity.setType(2);
                leaveReportUserEntity.setLeaveReportCode(entity.getLeaveCode());
            }
            leaveReportUserService.saveBatch(reportPo.getLeaveReportUserEntities());
            return entity.getLeaveCode();
        } else {
            String idStr = IdWorker.getIdStr();
            ReportEntity reportEntity = BeanUtil.copyProperties(reportPo, ReportEntity.class);
            reportEntity.setStatus(1);
            reportEntity.setReportCode(idStr);
            reportEntity.setCreateTime(LocalDateTime.now());
            reportEntity.setCreatePersonCode(user.getUserCode());
            reportEntity.setCreatePersonName(user.getUserName());
            reportEntity.setUpdateTime(LocalDateTime.now());
            reportEntity.setUpdatePersonCode(user.getUserCode());
            reportEntity.setUpdatePersonName(user.getUserName());
            this.save(reportEntity);
            for (LeaveReportUserEntity leaveReportUserEntity : reportPo.getLeaveReportUserEntities()) {
                leaveReportUserEntity.setCode(IdWorker.getIdStr());
                leaveReportUserEntity.setType(2);
                leaveReportUserEntity.setLeaveReportCode(idStr);
            }
            leaveReportUserService.saveBatch(reportPo.getLeaveReportUserEntities());
            return idStr;
        }

    }

    @Override
    public Page<ReportEntity> pageQueryReport(Page page, LeavePo leavePo) {
        UserCacheData user = ThreadUserContext.getCurrentCacheUser();
        leavePo.setUserCode(user.getUserCode());
        Page<ReportEntity>reportEntityPage=    this.getBaseMapper().pageQueryReport(page,leavePo);
        return reportEntityPage;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean deleteReport(String reportCode) {
        boolean isOk = false;
        isOk = this.remove(Wrappers.<ReportEntity>lambdaQuery()
                .eq(ReportEntity::getReportCode, reportCode));
        // todo 删除审批数据
        return isOk;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateStatusReport(ReportEntity reportEntity) {
        ReportEntity entity = this.getOne(Wrappers.<ReportEntity>lambdaQuery()
                .eq(ReportEntity::getReportCode, reportEntity.getReportCode()));
        entity.setStatus(reportEntity.getStatus());
        return this.updateById(entity);
    }

    @Override
    public CountLeaveAndReportVo countLeaveAndReport() {
        CountLeaveAndReportVo countLeaveAndReportVo = new CountLeaveAndReportVo();
        List<LeaveEntity> leaveEntities = leaveService.list(Wrappers.<LeaveEntity>lambdaQuery()
                .eq(LeaveEntity::getStatus, 2));
        if (CollUtil.isNotEmpty(leaveEntities)) {
            List<String> collect = leaveEntities.stream().map(LeaveEntity::getDuration).collect(Collectors.toList());
            List<BigDecimal> adds = new ArrayList<>();
            for (String s : collect) {
                adds.add(new BigDecimal(s));
            }
            BigDecimal decimal = adds.stream().reduce(BigDecimal::add).orElse(new BigDecimal(0));
            countLeaveAndReportVo.setSumLeave(decimal);
        }
        Calendar calendar = Calendar.getInstance();
        int year = calendar.get(Calendar.YEAR);
        int month = calendar.get(Calendar.MONTH) + 1;
        String yearMonth = null;
        if (month < 10) {
            yearMonth = year + "-" + "0" + month;
        } else {
            yearMonth = year + "-" + month;
        }
        List<LeaveEntity> leaveEntityList = leaveService.list(Wrappers.<LeaveEntity>lambdaQuery()
                .eq(LeaveEntity::getStatus, 2)
                .like(LeaveEntity::getCreateTime, yearMonth));
        if (CollUtil.isNotEmpty(leaveEntityList)) {
            List<String> collect = leaveEntityList.stream().map(LeaveEntity::getDuration).collect(Collectors.toList());
            List<BigDecimal> adds = new ArrayList<>();
            for (String s : collect) {
                adds.add(new BigDecimal(s));
            }
            BigDecimal decimal = adds.stream().reduce(BigDecimal::add).orElse(new BigDecimal(0));
            countLeaveAndReportVo.setMonthLeave(decimal);
        }


        List<ReportEntity> reportEntities = this.list(Wrappers.<ReportEntity>lambdaQuery()
                .eq(ReportEntity::getStatus, 2));
        if (CollUtil.isNotEmpty(reportEntities)) {
            List<String> collect = reportEntities.stream().map(ReportEntity::getDuration).collect(Collectors.toList());
            List<BigDecimal> adds = new ArrayList<>();
            for (String s : collect) {
                adds.add(new BigDecimal(s));
            }
            BigDecimal decimal = adds.stream().reduce(BigDecimal::add).orElse(new BigDecimal(0));
            countLeaveAndReportVo.setSumReport(decimal);
        }

        List<ReportEntity> reportEntityList = this.list(Wrappers.<ReportEntity>lambdaQuery()
                .eq(ReportEntity::getStatus, 2)
                .like(ReportEntity::getCreateTime, yearMonth));
        if (CollUtil.isNotEmpty(reportEntityList)) {
            List<String> collect = reportEntityList.stream().map(ReportEntity::getDuration).collect(Collectors.toList());
            List<BigDecimal> adds = new ArrayList<>();
            for (String s : collect) {
                adds.add(new BigDecimal(s));
            }
            BigDecimal decimal = adds.stream().reduce(BigDecimal::add).orElse(new BigDecimal(0));
            countLeaveAndReportVo.setMonthReport(decimal);
        }

        return countLeaveAndReportVo;
    }

    @Override
    public Page<AttendanceVo> attendance(Page page, AttendancePo attendancePo) {
        Page<AttendanceVo> attendanceVoPage = this.getBaseMapper().attendance(page, attendancePo);
        if (CollUtil.isNotEmpty(attendanceVoPage.getRecords())) {
            Set<String> useCodes = attendanceVoPage.getRecords().stream().map(AttendanceVo::getUserCode).collect(Collectors.toSet());
            List<LeaveReportUserEntity> leaveReportUserEntities = leaveReportUserService.list(Wrappers.<LeaveReportUserEntity>lambdaQuery()
                    .in(LeaveReportUserEntity::getUserCode, useCodes)
            .eq(LeaveReportUserEntity::getType,2));
            List<String> reportCodes = leaveReportUserEntities.stream().map(LeaveReportUserEntity::getLeaveReportCode).collect(Collectors.toList());
            List<ReportEntity> reportEntities = this.list(Wrappers.<ReportEntity>lambdaQuery()
                    .in(ReportEntity::getReportCode, reportCodes)
            .eq(ReportEntity::getStatus,2));
            Set<String> leaveCodes = reportEntities.stream().map(ReportEntity::getLeaveCode).collect(Collectors.toSet());
            List<LeaveEntity> leaveEntities = leaveService.list(Wrappers.<LeaveEntity>lambdaQuery()
                    .in(LeaveEntity::getLeaveCode, leaveCodes)
            .eq(LeaveEntity::getStatus,2));
            Map<String, LeaveEntity> stringLeaveEntityMap = leaveEntities.stream().collect(Collectors.toMap(LeaveEntity::getLeaveCode, Function.identity()));
            Map<String, ReportEntity> entityMap = reportEntities.stream().collect(Collectors.toMap(ReportEntity::getReportCode, Function.identity()));
            Map<String, List<LeaveReportUserEntity>> map = leaveReportUserEntities.stream().collect(Collectors.groupingBy(LeaveReportUserEntity::getUserCode));
            LocalDate now = LocalDate.now();
            for (AttendanceVo record : attendanceVoPage.getRecords()) {
                LocalDate enlistmentTime = record.getEnlistmentTime();
                // 年
                long yar = enlistmentTime.until(now, ChronoUnit.YEARS);
                record.setArmyAge(new BigDecimal(yar));
                if (map.containsKey(record.getUserCode())) {
                    List<LeaveReportUserEntity> reportUserEntities = map.get(record.getUserCode());
                    BigDecimal aaa = new BigDecimal(0);
                    BigDecimal bbb = new BigDecimal(0);
                    BigDecimal ccc = new BigDecimal(0);
                    BigDecimal ddd = new BigDecimal(0);
                    BigDecimal eee = new BigDecimal(0);
                    BigDecimal fff = new BigDecimal(0);
                    BigDecimal ggg = new BigDecimal(0);
                    BigDecimal hhh = new BigDecimal(0);
                    BigDecimal iii = new BigDecimal(0);
                    for (LeaveReportUserEntity reportUserEntity : reportUserEntities) {
                        if (entityMap.containsKey(reportUserEntity.getLeaveReportCode())) {
                            ReportEntity reportEntity = entityMap.get(reportUserEntity.getLeaveReportCode());
                            if (stringLeaveEntityMap.containsKey(reportEntity.getLeaveCode())) {
                                LeaveEntity leaveEntity = stringLeaveEntityMap.get(reportEntity.getLeaveCode());
                                if (Objects.nonNull(leaveEntity)){
                                    switch (leaveEntity.getType()) {
                                        case 1:
                                            aaa=aaa.add(new BigDecimal(reportEntity.getDuration()));
                                            break;
                                        case 2:
                                            bbb=bbb.add(new BigDecimal(reportEntity.getDuration()));
                                            break;
                                        case 3:
                                            ccc=ccc.add(new BigDecimal(reportEntity.getDuration()));
                                            break;
                                        case 4:
                                            ddd=ddd.add(new BigDecimal(reportEntity.getDuration()));
                                            break;
                                        case 5:
                                            eee=eee.add(new BigDecimal(reportEntity.getDuration()));
                                            break;
                                        case 6:
                                            fff=fff.add(new BigDecimal(reportEntity.getDuration()));
                                            break;
                                        case 7:
                                            ggg=ggg.add(new BigDecimal(reportEntity.getDuration()));
                                            break;
                                        case 8:
                                            hhh=hhh.add(new BigDecimal(reportEntity.getDuration()));
                                            break;
                                        case 9:
                                            iii=iii.add(new BigDecimal(reportEntity.getDuration()));
                                            break;
                                    }
                                }
                            }
                        }
                        record.setOne(aaa);
                        record.setTwo(bbb);
                        record.setThree(ccc);
                        record.setFour(ddd);
                        record.setFive(eee);
                        record.setSix(fff);
                        record.setSeven(ggg);
                        record.setEight(hhh);
                        record.setNine(iii);

                    }
                }

            }
        }
        return attendanceVoPage;
    }
}
